// fitsconverter.cpp
#include "fitsconverter.h"
#include "fitsio.h"
#include <fstream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <algorithm>
#include <memory>
#include <sys/stat.h>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QRegularExpression>
#include <QDateTime>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QValueAxis>
#include <csignal>  // 添加这个头文件
#include <QNetworkInterface>  // 网络接口相关
#include <QHostAddress>       // IP地址处理
#include <QDebug>

// 读取二进制文件
std::vector<uint16_t> FitsConverter::readBinaryFile(const std::string& filename) {
    std::ifstream file(filename, std::ios::binary | std::ios::ate);
    if (!file) {
        throw std::runtime_error("无法打开文件: " + filename);
    }

    std::streamsize size = file.tellg();
    file.seekg(0, std::ios::beg);

    if (size % sizeof(uint16_t) != 0) {
        throw std::runtime_error("文件大小不是uint16_t的整数倍");
    }

    std::vector<uint16_t> buffer(size / sizeof(uint16_t));
    if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
        throw std::runtime_error("读取文件失败: " + filename);
    }

    // 确保小端序读取（如果Python版本是小端序）
    // 根据您的Python脚本使用的字节序决定是否需要交换
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    for (auto& val : buffer) {
        val = __builtin_bswap16(val);
    }
#endif

    return buffer;
}

// 分割数据到列
std::vector<std::vector<uint16_t>> FitsConverter::splitDataIntoColumns(
    const std::vector<uint16_t>& data, int numColumns) {

    if (data.size() % numColumns != 0) {
        throw std::runtime_error("数据长度必须是列数的整数倍");
    }

    size_t elementsPerColumn = data.size() / numColumns;
    std::vector<std::vector<uint16_t>> columns(numColumns, std::vector<uint16_t>(elementsPerColumn));

    // 更高效的列分割方式，确保顺序与Python一致
    for (size_t i = 0; i < elementsPerColumn; ++i) {
        for (int j = 0; j < numColumns; ++j) {
            columns[j][i] = data[i * numColumns + j];
        }
    }

    return columns;
}

// 重塑列数据 (4700x1250)
std::vector<std::vector<uint16_t>> FitsConverter::reshapeColumns(
    const std::vector<std::vector<uint16_t>>& columns, int rows, int cols) {

    std::vector<std::vector<uint16_t>> reshapedColumns;
    reshapedColumns.reserve(columns.size());

    for (const auto& col : columns) {
        if (col.size() != static_cast<size_t>(rows * cols)) {
            throw std::runtime_error("列数据大小与重塑尺寸不匹配");
        }

        std::vector<uint16_t> reshaped(rows * cols);
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                reshaped[i * cols + j] = col[j * rows + i]; // 转置重塑
            }
        }
        reshapedColumns.push_back(reshaped);
    }

    return reshapedColumns;
}

// 拼接列数据 (2行8列)，完全按照Python版本的逻辑
std::vector<uint16_t> FitsConverter::concatenateColumns(
    const std::vector<std::vector<uint16_t>>& columns) {

    const int numRows = 2;
    const int numColumnsPerRow = 8;
    const int colHeight = 4700;
    const int colWidth = 1250;

    if (columns.size() != 16) {
        throw std::runtime_error("需要16列数据");
    }

    // 验证每列数据大小
    for (const auto& col : columns) {
        if (col.size() != colHeight * colWidth) {
            throw std::runtime_error("列数据大小不正确");
        }
    }

    // 计算最终图像尺寸
    const int totalWidth = colWidth * numColumnsPerRow;
    const int totalHeight = colHeight * numRows;
    std::vector<uint16_t> combinedImage(totalWidth * totalHeight, 0);

    // 定义与Python版本完全相同的通道重排顺序
    const std::vector<int> reorder_lower = {2, 3, 0, 1, 6, 7, 4, 5};  // 对应Python的[3,4,1,2,7,8,5,6]
    const std::vector<int> reorder_upper = {5, 4, 7, 6, 1, 0, 3, 2};  // 对应Python的[c,d,a,b,g,h,e,f]

    for (int row = 0; row < numRows; ++row) {
        for (int col = 0; col < numColumnsPerRow; ++col) {
            // 计算原始通道索引
            int origChan;
            if (row == 0) {
                origChan = reorder_lower[col];
            } else {
                origChan = 8 + reorder_upper[col]; // 上排通道
            }

            if (origChan < 0 || origChan >= 16) {
                throw std::runtime_error("无效的通道索引");
            }

            const auto& column = columns[origChan];

            // 计算目标位置
            int destX = col * colWidth;
            int destY = row * colHeight;

            // 复制数据，同时应用翻转
            for (int y = 0; y < colHeight; ++y) {
                for (int x = 0; x < colWidth; ++x) {
                    // 计算源位置，考虑翻转
                    int srcY = y;
                    int srcX = x;

                    // 底行需要垂直翻转
                    if (row == 1) {
                        srcY = colHeight - 1 - y;
                    }

                    // 右半图像水平翻转 (通道4-7和12-15)
                    if (origChan % 8 >= 4) {
                        srcX = colWidth - 1 - x;
                    }

                    // 计算源位置索引
                    int srcPos = srcY * colWidth + srcX;

                    // 确保不越界
                    if (srcPos >= 0 && srcPos < static_cast<int>(column.size())) {
                        int destPos = (destY + y) * totalWidth + (destX + x);
                        if (destPos >= 0 && destPos < static_cast<int>(combinedImage.size())) {
                            combinedImage[destPos] = column[srcPos];
                        }
                    }
                }
            }
        }
    }

    return combinedImage;
}

// 写入FITS文件
bool FitsConverter::writeFitsFile(const std::string& filePath,
                                  const std::vector<uint16_t>& imageData,
                                  int width, int height,
                                  const std::vector<std::pair<std::string, std::string>>& keywords) {
    fitsfile* fitsFile = nullptr;
    int status = 0;

    // 删除已存在的文件
    remove(filePath.c_str());

    // 创建新FITS文件
    fits_create_file(&fitsFile, ("!" + filePath).c_str(), &status);
    if (status) {
        char errText[FLEN_STATUS];
        fits_get_errstatus(status, errText);
        throw std::runtime_error("无法创建FITS文件: " + std::string(errText));
    }

    // 创建图像HDU
    long naxes[2] = {width, height};
    fits_create_img(fitsFile, USHORT_IMG, 2, naxes, &status);
    if (status) {
        fits_report_error(stderr, status);
        throw std::runtime_error("无法创建图像HDU");
    }

    // 添加关键字
    for (const auto& kv : keywords) {
        std::string key = kv.first.substr(0, 8); // FITS关键字最多8字符
        std::string value = kv.second;
        std::string comment = "";

        fits_update_key(fitsFile, TSTRING, key.c_str(), (void*)value.c_str(), comment.c_str(), &status);
        if (status) {
            fits_report_error(stderr, status);
            throw std::runtime_error("无法写入关键字");
        }
    }

    // 写入图像数据
    long fpixel[2] = {1, 1};
    fits_write_pix(fitsFile, TUSHORT, fpixel, imageData.size(), (void*)imageData.data(), &status);
    if (status) {
        fits_report_error(stderr, status);
        throw std::runtime_error("无法写入图像数据");
    }

    // 关闭FITS文件
    fits_close_file(fitsFile, &status);
    if (status) {
        fits_report_error(stderr, status);
        throw std::runtime_error("无法关闭FITS文件");
    }

    return true;
}

// 主处理函数（匹配Python脚本）
bool FitsConverter::processBinToFits(const std::string& binPath,
                                     const std::string& outputDir,
                                     const std::string& baseFilename,
                                     const std::vector<std::pair<std::string, std::string>>& keywords) {
    try {
        // 确保输出目录存在
        if (mkdir(outputDir.c_str(), 0755) != 0 && errno != EEXIST) {
            throw std::runtime_error("无法创建输出目录: " + outputDir);
        }

        // 1. 读取二进制文件
        auto data = readBinaryFile(binPath);

        // 2. 分割数据为16列
        auto columns = splitDataIntoColumns(data, 16);

        // 3. 重塑每列为4700x1250
        auto reshapedColumns = reshapeColumns(columns, 4700, 1250);

        // 4. 拼接为2行8列的图像，完全按照Python版本的逻辑
        auto combinedImage = concatenateColumns(reshapedColumns);

        // 5. 保存为FITS文件
        std::string outputFile = outputDir + "/" + baseFilename + ".fits";
        bool success = writeFitsFile(outputFile, combinedImage, 1250 * 8, 4700 * 2, keywords);

        return success;
    } catch (const std::exception& e) {
        throw std::runtime_error("BIN转FITS失败: " + std::string(e.what()));
    }
}

void MainWindow::processCameraHeader(const QString& response)
{

    QMap<QString, QString> params;
    QStringList parts = response.split('$');

    for (const QString& part : parts) {
        int eqPos = part.indexOf('=');
        if (eqPos > 0) {
            QString key = part.left(eqPos);
            QString value = part.mid(eqPos+1);
            params[key] = value;
        }
    }

    // 更新当前曝光信息
    m_currentExpInfo.tag = params.value("tag");
    m_currentExpInfo.expStart = parseCameraTimestamp(params.value("exp_start"));
    m_currentExpInfo.expEnd = parseCameraTimestamp(params.value("exp_end"));
    m_currentExpInfo.readoutStart = parseCameraTimestamp(params.value("readout_start"));

    // 验证时间戳有效性
    if (!m_currentExpInfo.expStart.isValid() ||
        !m_currentExpInfo.expEnd.isValid() ||
        !m_currentExpInfo.readoutStart.isValid()) {
        LOG_CAMERA("Parsed an invalid timestamp");
        m_currentExpInfo = ExposureInfo(); // 重置为无效状态
    }
}

bool MainWindow::convertBinToFits(const QString& binPath,
                                  const QString& fitsPath,
                                  const QString& baseFilename,
                                  const std::vector<std::pair<std::string, std::string>>& keywords)
{
    // 准备关键字列表（包含原有keywords和时间戳）
    std::vector<std::pair<std::string, std::string>> allKeywords = keywords;

    // 如果当前曝光信息匹配，添加时间戳关键字
    if (!m_currentExpInfo.tag.isEmpty() && m_currentExpInfo.tag == baseFilename.right(11)) {
        // 计算曝光时间（秒）
        double expTime = m_currentExpInfo.expStart.msecsTo(m_currentExpInfo.expEnd) / 1000.0;

        // 添加时间戳关键字
        allKeywords.emplace_back("EXPSTART", m_currentExpInfo.expStart.toString("yyyy-MM-ddThh:mm:ss.zzz").toStdString());
        allKeywords.emplace_back("EXPEND", m_currentExpInfo.expEnd.toString("yyyy-MM-ddThh:mm:ss.zzz").toStdString());
        allKeywords.emplace_back("READOUTS", m_currentExpInfo.readoutStart.toString("yyyy-MM-ddThh:mm:ss.zzz").toStdString());
        allKeywords.emplace_back("EXPTIME", QString::number(expTime, 'f', 3).toStdString());

        LOG_CAMERA(QString("Add to FITS Header: EXPSTART=%1, EXPEND=%2, READOUTS=%3, EXPTIME=%4")
                       .arg(m_currentExpInfo.expStart.toString("yyyy-MM-dd hh:mm:ss.zzz"))
                       .arg(m_currentExpInfo.expEnd.toString("yyyy-MM-dd hh:mm:ss.zzz"))
                       .arg(m_currentExpInfo.readoutStart.toString("yyyy-MM-dd hh:mm:ss.zzz"))
                       .arg(expTime));
    }

    // 原有的转换逻辑（使用包含时间戳的allKeywords）
    try {
        bool result = FitsConverter::processBinToFits(
            binPath.toStdString(),
            fitsPath.toStdString(),
            baseFilename.toStdString(),
            allKeywords  // 传入所有关键字（包含时间戳）
            );

        if (!result) {
            LOG_CAMERA(QString("BIN2FITS fialed: %1").arg(binPath));
            return false;
        }

        QString fitsFile = fitsPath + "/" + baseFilename + ".fits";
        if (!QFile::exists(fitsFile)) {
            LOG_CAMERA(QString("The FITS file has not been generated: %1").arg(fitsFile));
            return false;
        }

        LOG_CAMERA(QString("BIN2FITS successfully: %1 -> %2").arg(binPath).arg(fitsFile));
        return true;
    } catch (const std::exception& e) {
        LOG_CAMERA(QString("An exception occurred during the conversion process: %1").arg(e.what()));
        return false;
    }
}

void MainWindow::on_btnmergefits_clicked(){
    QStringList fitsFilePaths;
    QString fitsFile0 = fitsSavePath + "/" + "00" + ".fits";
    QString fitsFile1 = fitsSavePath + "/" + "01" + ".fits";
    QString fitsFile2 = fitsSavePath + "/" + "02" + ".fits";
    QString fitsFile3 = fitsSavePath + "/" + "03" + ".fits";
    fitsFilePaths.append(fitsFile0);
    fitsFilePaths.append(fitsFile1);
    fitsFilePaths.append(fitsFile2);
    fitsFilePaths.append(fitsFile3);

    QString mergedFitsPath = fitsSavePath + "/" + currentBaseFilename + "_merged.fits";
    if (mergeFitsFiles(fitsFilePaths, mergedFitsPath)) {
        LOG_CAMERA(QString("成功合并FITS文件: %1").arg(mergedFitsPath));

        // 可选：删除原始单个FITS文件
        //for (const QString &fitsFile : fitsFilePaths) {
        //QFile::remove(fitsFile);
        //}
    } else {
        LOG_CAMERA("合并FITS文件失败");
    }

}

bool MainWindow::mergeFitsFiles(const QStringList& inputFiles, const QString& outputFile)
{
    fitsfile *outfits = nullptr;
    int status = 0;

    // 删除已存在的输出文件
    remove(outputFile.toLocal8Bit().constData());

    // 创建新的FITS文件
    if (fits_create_file(&outfits, ("!" + outputFile).toLocal8Bit().constData(), &status)) {
        char errText[FLEN_STATUS];
        fits_get_errstatus(status, errText);
        LOG_CAMERA(QString("Failed to create a merged FITS file: %1").arg(errText));
        return false;
    }

    // 逐个添加输入文件作为HDU
    for (const QString &inputFile : inputFiles) {
        fitsfile *infits = nullptr;

        // 打开输入文件
        if (fits_open_file(&infits, inputFile.toLocal8Bit().constData(), READONLY, &status)) {
            char errText[FLEN_STATUS];
            fits_get_errstatus(status, errText);
            LOG_CAMERA(QString("Failed to open the input FITS file: %1 - %2").arg(inputFile).arg(errText));
            fits_close_file(outfits, &status);
            return false;
        }

        // 获取输入HDU信息
        int hdutype;
        if (fits_get_hdu_type(infits, &hdutype, &status)) {
            fits_close_file(infits, &status);
            fits_close_file(outfits, &status);
            return false;
        }

        // 复制HDU到输出文件
        if (fits_copy_hdu(infits, outfits, 0, &status)) {
            char errText[FLEN_STATUS];
            fits_get_errstatus(status, errText);
            LOG_CAMERA(QString("Failed to copy HDU.: %1 - %2").arg(inputFile).arg(errText));
            fits_close_file(infits, &status);
            fits_close_file(outfits, &status);
            return false;
        }

        // 关闭输入文件
        fits_close_file(infits, &status);
    }

    // 添加合并信息到历史记录
    QString history = QString("Merged from %1 files at %2")
                          .arg(inputFiles.size())
                          .arg(QDateTime::currentDateTime().toString(Qt::ISODate));
    fits_write_history(outfits, history.toLocal8Bit().constData(), &status);

    // 关闭输出文件
    if (fits_close_file(outfits, &status)) {
        char errText[FLEN_STATUS];
        fits_get_errstatus(status, errText);
        LOG_CAMERA(QString("Failed to close the merged FITS file.: %1").arg(errText));
        return false;
    }

    return true;
}

// 收集手动拍摄的头信息
std::vector<std::pair<std::string, std::string>> MainWindow::collectManualHeaderInfo() {
    std::vector<std::pair<std::string, std::string>> keywords;

    // 标准关键字
    keywords.push_back({"INSTRUME", "BLUE"});
    keywords.push_back({"OBSERVER", "XYH"});
    keywords.push_back({"TELESCOP", "MEPHISTO"});
    keywords.push_back({"EXPTIME", QString::number(ui->doubleSpinBoxExposureTime->value()).toStdString()});
    keywords.push_back({"DATE-OBS", QDateTime::currentDateTime().toString(Qt::ISODate).toStdString()});

    // 从界面获取手动输入的信息
    if (!ui->lineEditObjName->text().isEmpty()) {
        keywords.push_back({"OBJ_NAME", ui->lineEditObjName->text().toStdString()});
    }
    if (!ui->lineEditFwName->text().isEmpty()) {
        keywords.push_back({"FW_NAME", ui->lineEditFwName->text().toStdString()});
    }
    if (!ui->lineEditImgNum->text().isEmpty()) {
        keywords.push_back({"IMG_NUM", ui->lineEditImgNum->text().toStdString()});
    }
    QString frameType = ui->comBoxframetype->currentData().toString();
    std::string darkMode = (frameType == "bs" || frameType == "dk") ? "1" : "0";
    // 其他复选框状态

    if (m_currentExpInfo.isValid()) {
        keywords.push_back({"RATE", m_currentExpInfo.readoutRate.toStdString()});
    }
    keywords.push_back({"FRAMETYPE", frameType.toStdString()});
    keywords.push_back({"DARK", darkMode});
    keywords.push_back({"PINNING", ui->checkBoxPinning->isChecked() ? "1" : "0"});
    keywords.push_back({"DUMP", ui->checkBoxDump->isChecked() ? "1" : "0"});

    return keywords;
}

double MainWindow::calculateFitsMedian(const QString& fitsPath)
{
    fitsfile* fitsFile = nullptr;
    int status = 0;
    long fpixel[2] = {1, 1};
    long naxes[2] = {0, 0};
    double median = -999.0;

    // 1. 打开FITS文件
    QByteArray filePath = QDir::toNativeSeparators(fitsPath).toLocal8Bit();
    if (fits_open_file(&fitsFile, filePath.constData(), READONLY, &status)) {
        char errText[FLEN_STATUS];
        fits_get_errstatus(status, errText);
        throw std::runtime_error(QString("打开FITS文件失败: %1").arg(errText).toStdString());
    }

    // 2. 获取图像尺寸
    if (fits_get_img_size(fitsFile, 2, naxes, &status)) {
        fits_close_file(fitsFile, &status);
        throw std::runtime_error("获取图像尺寸失败");
    }

    long npixels = naxes[0] * naxes[1];
    if (npixels <= 0) {
        fits_close_file(fitsFile, &status);
        throw std::runtime_error("无效的图像尺寸");
    }

    // 3. 读取图像数据
    std::vector<float> buffer(npixels);
    if (fits_read_pix(fitsFile, TFLOAT, fpixel, npixels, nullptr, buffer.data(), nullptr, &status)) {
        fits_close_file(fitsFile, &status);
        throw std::runtime_error("读取图像数据失败");
    }

    // 4. 计算中值
    auto mid = buffer.begin() + npixels / 2;
    std::nth_element(buffer.begin(), mid, buffer.end());
    median = *mid;

    // 如果是偶数个像素，取中间两个的平均值
    if (npixels % 2 == 0) {
        auto mid2 = std::max_element(buffer.begin(), mid);
        median = (*mid + *mid2) / 2.0;
    }

    // 5. 关闭文件
    fits_close_file(fitsFile, &status);

    return median;
}

bool MainWindow::updateFitsHeader(const QString& fitsPath, const QJsonObject& headerData)
{
    fitsfile* fitsFile = nullptr;
    int status = 0;
    char errText[FLEN_STATUS] = {0};

    // 1. 打开文件
    QByteArray filePath = QDir::toNativeSeparators(fitsPath).toLocal8Bit();
    if (fits_open_file(&fitsFile, filePath.constData(), READWRITE, &status)) {
        fits_get_errstatus(status, errText);
        LOG_CAMERA(QString("Failed to open the FITS file.: %1").arg(errText));
        return false;
    }

    // 2. 更新关键字
    for (auto it = headerData.begin(); it != headerData.end(); ++it) {
        QString key = it.key();
        QString value = it.value().isString() ? it.value().toString()
                                              : it.value().toVariant().toString();

        QByteArray keyData = key.toLocal8Bit();
        QByteArray valueData = value.toLocal8Bit();

        // 先删除已存在的关键字（忽略错误）
        fits_delete_key(fitsFile, keyData.constData(), &status);
        status = 0;

        // 写入新关键字
        if (fits_update_key(fitsFile, TSTRING,
                            keyData.constData(),
                            valueData.data(),  // 注意这里用 data() 而不是 constData()
                            nullptr, &status)) {
            fits_get_errstatus(status, errText);
            LOG_CAMERA(QString("Failed to update the keyword: %1").arg(errText));
            status = 0;
            continue;
        }
    }

    // 3. 关闭文件
    if (fits_close_file(fitsFile, &status)) {
        fits_get_errstatus(status, errText);
        LOG_GENERAL(QString("Failed to close the FITS file: %1").arg(errText));
        return false;
    }

    return true;
}
